/*
原本的pwm.c里定义的接口使用起来并不方便，因此在此对其进行封装。另外在开发指南中有如下注意事项：

在调用uapi_pwm_deinit接口之前，需要先调用uapi_pwm_close接口。关于这一项我是遇到过问题的。我开启PWM通道、加了死循环
后就没管后面的内容，在循环结束时只调用了deinit，导致每运行一段时间单片机就会重启一次，串口疯狂打印。如果你也遇到这样
的问题，可以排查一下是不是违反了这一条。

PWM调用uapi_pwm_stop/uapi_pwm_close时不支持在中断中调用。 
PWM不支持占空比为0。 
PWM不支持多路互补输出。 
深睡唤醒之后需要先配置复用关系，再调用uapi_pwm_deinit接口去初始化，之后调用uapi_pwm_init 接口初始化。 
*/
#include "pinctrl.h"
#include "pwm.h"
#include "osal_debug.h"
#include "cmsis_os2.h"
#include "app_init.h"
#include "tcxo.h"

#include "main.h"

#define PWM_PIN_MODE  1//所有引脚的PWM模式都对应模式1

/*
根据现有经验，周期（单位为ns）=（低电平+高电平）*12.8，虽然不知道为什么是这样，也可能有误差，或许应该要乘12.5才对。
周期（以及可以由它唯一确定的频率）无法直接设置，而是这样由高、低电平时间共同决定的，因此在下面定义一个总的时间。当
它为5000时频率为15625Hz，对于一般的电机是较为适用的。
*/
#define TOTAL_TIME 50000
/*占空比修改函数中引用到的库函数uapi_pwm_update_duty_ratio需要在定义了CONFIG_PWM_USING_V150之后才会在pwm.h中进行
声明、pwm.c中进行定义，否则会报错说不认识这个函数，所以我干脆改了这两个文件的内容，把这个条件给删了。这两个文件分别
在：
drivers\drivers\driver\pwm\pwm.c
include\driver\pwm.h
*/
pwm_config_t cfg_no_repeat = {
        TOTAL_TIME / 100 * 50,//低电平
        TOTAL_TIME / 100 * 50,//高电平。之所以先除再乘是因为防止数据溢出
        0,
        0,
        true
    };//PWM配置参数。主要就是改改高低电平时间的总和和比例

// /* PWM注册中断回调函数。在我们的工程中好像用不到，就干脆把它注释掉了 */  
// static errcode_t pwm_sample_callback(uint8_t channel)
// {
//     osal_printk("PWM %d, cycle done. \r\n", channel);
//     return ERRCODE_SUCC;
// }

/**
 * @brief  将指定引脚配置为PWM输出脚。默认是只配置而不在配置完了之后立即开始输出的，如果要开启，按官方的说法用接口
 * uapi_pwm_start去单独指定是行不通的（也不能单独关闭），尚不清楚是什么原因。不过按分组启动、停止一直都是可行的。在
 * 本函数里将被指定的通道单独设定为一组，组的ID就设定为通道，所以后面也可以就用start_group传入通道来同样地实现开启
 * 单独通道。另外通道四至七似乎也开启不了
 * @param  [in]  pin 指定的引脚。请查阅IO复用关系表，找到某个引脚对应的PWM通道，某个通道可能对应多个引脚
 * @param  [in]  channel 指定引脚对应的通道
 * @param  [in]  duty 占空比。百分之多少的那个“多少”，即如果需要一个高低电平时间刚好对半开的PWM波，这里就填50
 * @retval None
 * @endif
 */
void pwm_init(pin_t pin, uint8_t channel, uint8_t duty)
{
    /* 设置可作为PWM IO的模式 */ 
    uapi_pin_set_mode(pin, PWM_PIN_MODE);
    uapi_pwm_deinit();
    uapi_pwm_init();
    /* 打开指定chanel的PWM */
    uapi_pwm_open(channel, &cfg_no_repeat);
    // /* 注册回调函数 */ 
    // uapi_pwm_unregister_interrupt(channel);
    // uapi_pwm_register_interrupt(channel, pwm_sample_callback);
    /* 每个通道单独一组，分别指定 */
    uint8_t channel_id[1] = {channel};
    uapi_pwm_set_group(channel, channel_id, 1);
}

/**
 * @brief  更新打开的PWM上的占空比。在这个项目里因为用到的PWM通道都很靠前，一通道一组的话引脚、通道、分组都是可以混
 * 用的。有些引脚和通道在数值上并不相同，请自行查找参考手册。
 * @param  [in]  channel PWM通道，参考 @ref pwm_channel_t 。
 * @param  [in]  duty 新的占空比
 * @retval ERRCODE_SUCC 成功。
 * @retval Other        失败，参考 @ref errcode_t 。
 * @endif
 */
void pwm_update_duty_ratio(pin_t pin, uint8_t channel, uint8_t duty)
{
    uapi_pwm_close(pin);
    if(duty == 0)
    {
        //不支持占空比为0，所以在此加个判断，直接把通道关闭掉后就不再做任何处理。
        return;
    }
    cfg_no_repeat.low_time = TOTAL_TIME / 100 * (100 - duty);
    cfg_no_repeat.high_time = TOTAL_TIME / 100 * duty;
    uapi_pwm_open(channel, &cfg_no_repeat);
    uapi_pwm_start_group(pin);
}

//把所有需要用到PWM的通道一起初始化了
void init_all_pwm(void)
{
    pwm_init(FAN, FAN, 50);
}
